package com.xhwl.data.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.xhwl.common.dto.cent.sdata.AreaDTO;
import com.xhwl.common.dto.cent.sdata.space.ErrorSpace;
import com.xhwl.common.enums.OperationTypeEnum;
import com.xhwl.common.enums.OrganizationTypeEnum;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.sdata.Account;
import com.xhwl.common.pojo.cent.sdata.Area;
import com.xhwl.common.pojo.cent.sdata.Block;
import com.xhwl.common.pojo.cent.sdata.Organization;
import com.xhwl.common.query.cent.sdata.AreaQuery;
import com.xhwl.common.query.cent.sdata.OrganizationQuery;
import com.xhwl.common.utils.StringUtils;
import com.xhwl.data.dao.IAreaDao;
import com.xhwl.data.dao.IOrganizationDao;
import com.xhwl.data.mq.producer.OrganizationProducer;
import com.xhwl.data.pojo.annotation.OrganizationHandle;
import com.xhwl.data.service.IAreaService;
import com.xhwl.data.service.IOrganizationService;
import com.xhwl.data.util.AutoCodeUtils;
import com.xhwl.data.util.CodePrefixConstant;
import org.apache.commons.collections4.CollectionUtils;
import org.checkerframework.checker.units.qual.A;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: luyi
 * @Description:
 * @Date: Create in 15:13 2021/1/21
 */
@Service
public class AreaServiceImpl extends ServiceImpl<IAreaDao, Area> implements IAreaService {

    @Autowired
    private IAreaDao areaDao;

    @Autowired
    private IOrganizationDao organizationDao;

    @Autowired
    private IOrganizationService organizationService;

    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private OrganizationProducer organizationProducer;

    private static final Logger log = LoggerFactory.getLogger(AreaServiceImpl.class);

    @Override
    @Transactional
    @OrganizationHandle(operationType = OperationTypeEnum.CREATE)
    public ResultJson create(AreaDTO areaDTO) {
        Area area = new Area();
        BeanUtils.copyProperties(areaDTO, area);
        area.setIsDelete(false);
        areaDao.insert(area);

        if (StringUtils.isEmpty(area.getCode())) {
            area.setCode(AutoCodeUtils.codeFormat(CodePrefixConstant.AREA_PREFIX, area.getId(), CodePrefixConstant.CODE_LENGTH));
            areaDao.updateById(area);
        }
        Organization org = organizationService.getById(areaDTO.getOrganizationId());
        org.setCode(area.getCode());
        organizationService.update(org);
        return ResultJson.success("操作成功", area);
    }

    @Override
    @Transactional
    public ResultJson update(AreaDTO areaDTO) {
        Area area = new Area();
        BeanUtils.copyProperties(areaDTO, area);

        Area old = areaDao.selectById(area.getId());
        if (null == old) {
            log.error("更新区域失败，旧区域 {} 不存在", area.getId());
            return ResultJson.fail("数据异常");
        }
        Organization organization = organizationDao.selectById(old.getOrganizationId());
        organization.setName(area.getName());
        organization.setSortField(area.getSortField());
        if (StringUtils.isNotEmpty(areaDTO.getCode())) {
            organization.setCode(areaDTO.getCode());
        }
        if (null != old.getSortField() &&!old.getSortField().equals(areaDTO.getSortField())){
            List<Organization> organizationList = organizationService.list(new OrganizationQuery().withParentId(organization.getParentId()));
            List<Integer> orgIds = organizationList.stream().filter(i->null != i.getSortField()).map(Organization::getId).collect(Collectors.toList());
            UpdateWrapper<Area> updateWrapper = new UpdateWrapper<>();
            updateWrapper.in("organization_id",orgIds);
            UpdateWrapper<Organization> organizationUpdateWrapper = new UpdateWrapper<>();
            organizationUpdateWrapper.in("id",orgIds);
            if (old.getSortField() > areaDTO.getSortField()){
                //大改小 小于等于'大'并且大于等于'小'的加1
                updateWrapper.ge("sort_field",areaDTO.getSortField());
                updateWrapper.le("sort_field",old.getSortField());
                organizationUpdateWrapper.ge("sort_field",areaDTO.getSortField());
                organizationUpdateWrapper.le("sort_field",old.getSortField());
                updateWrapper.setSql("sort_field = sort_field+1");
                organizationUpdateWrapper.setSql("sort_field = sort_field+1");
            }else {
                //小改大 大于'小'并且小于等于'大'的减1
                updateWrapper.le("sort_field",areaDTO.getSortField());
                updateWrapper.gt("sort_field",old.getSortField());
                organizationUpdateWrapper.le("sort_field",areaDTO.getSortField());
                organizationUpdateWrapper.gt("sort_field",old.getSortField());
                updateWrapper.setSql("sort_field = sort_field-1");
                organizationUpdateWrapper.setSql("sort_field = sort_field-1");
            }
            this.update(updateWrapper);
            organizationService.update(organizationUpdateWrapper);
        }
        ResultJson update = organizationService.update(organization);
        if (!update.getState()) {
            return update;
        }
        areaDao.updateById(area);
        return ResultJson.success();
    }

    @Override
    public ResultJson refreshSort(AreaQuery areaQuery) {
        List<Area> areas = areaDao.list(areaQuery);
        List<Organization> organizationList = organizationService.list(new OrganizationQuery().withIds(areas.stream().map(Area::getOrganizationId).collect(Collectors.toList())));
        organizationList = organizationList.stream().distinct().collect(Collectors.toList());
        Map<Integer,Organization> organizationMap = organizationList.stream().collect(Collectors.toMap(Organization::getId, Function.identity()));
//        List<List<Area>> parts = Lists.partition(areas, 500);
        for (int i = 0; i < areas.size(); i++) {
            areas.get(i).setSortField(i+1);
            JSONObject jsonObject = JSONObject.parseObject(areas.get(i).getExpand());
            if (null != jsonObject){
                jsonObject.put("sortField",i+1);
                areas.get(i).setExpand(jsonObject.toJSONString());
            }
            organizationMap.get(areas.get(i).getOrganizationId()).setSortField(i+1);
        }
        this.updateBatchById(areas);
        organizationService.updateBatchById(organizationMap.values());
        return ResultJson.success("刷新成功");
    }

    @Override
    public Page<Area> page(AreaQuery areaQuery, Page page) {
        return areaDao.page(page, areaQuery);
    }

    @Override
    public ResultJson delete(Integer id, Account account) {
        Area area = areaDao.selectById(id);
        if (null == area) {
            return ResultJson.fail("该区域不存在");
        }
        //下级判断
        QueryWrapper<Organization> organizationQueryWrapper = new QueryWrapper<>();
        organizationQueryWrapper.eq("parent_id", area.getOrganizationId());
        List<Organization> organizations = organizationDao.selectList(organizationQueryWrapper);
        if (!organizations.isEmpty()) {
            return ResultJson.fail("删除失败，存在下级数据");
        }
        areaDao.deleteById(id);
        Organization organization = organizationService.getById(area.getOrganizationId());
        organizationProducer.deletePush(JSON.toJSONString(Collections.singleton(organization)));
        organizationDao.deleteById(area.getOrganizationId());
        return ResultJson.success("操作成功");
    }

    @Override
    public List<Area> list(AreaQuery areaQuery) {
        if (null != areaQuery) {
            return areaDao.list(areaQuery);
        }
        return Collections.emptyList();
    }

    @Override
    public Area one(AreaQuery areaQuery, Account account) {
        List<Area> list = areaDao.list(areaQuery);
        if (list.isEmpty()) {
            return null;
        } else if (list.size() > 1) {
            log.warn("区域查询到了多个结果");
            return null;
        } else {
            return list.get(0);
        }
    }

    @Override
    @Transactional
    public ResultJson batchCreate(List<AreaDTO> areas) {
        if (CollectionUtils.isEmpty(areas)) {
            return ResultJson.fail("参数错误");
        }
        AreaServiceImpl bean = applicationContext.getBean(this.getClass());
        for (AreaDTO areaDTO : areas) {
            bean.create(areaDTO);
        }
        return ResultJson.success();
    }

    @Override
    @Transactional
    public ResultJson batchCreateFaster(List<AreaDTO> areaDTOS) {
        if (CollectionUtils.isEmpty(areaDTOS)) {
            return ResultJson.fail("无效的数据");
        }

        List<ErrorSpace> errors = new ArrayList<>();
        // 数据处理 1 分组 2 校验
        Set<Integer> collect = areaDTOS.stream().map(i -> i.getParentId()).collect(Collectors.toSet());
        Map<Integer, List<AreaDTO>> parentAndChildMap = new HashMap<>();
        for (Integer i : collect) {
            parentAndChildMap.put(i, areaDTOS.stream().filter(j -> i.equals(j.getParentId())).collect(Collectors.toList()));
        }
        for (Map.Entry<Integer, List<AreaDTO>> entry : parentAndChildMap.entrySet()) {
            Integer parentId = entry.getKey();
            Organization organization = organizationDao.selectById(parentId);

            // 上级信息校验
            if (null == organization) {
                for (AreaDTO areaDTO : entry.getValue()) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("上级信息不存在");
                    errorSpace.setObj(areaDTO);
                    errors.add(errorSpace);
                }
                continue;
            }

            // 名称校验
            List<AreaDTO> value = entry.getValue();
            Map<String, AreaDTO> map = new HashMap<>();
            Map<String, AreaDTO> buildingDB = new HashMap<>();
            QueryWrapper<Organization> organizationQueryWrapper = new QueryWrapper<>();
            organizationQueryWrapper.select("name");
            organizationQueryWrapper.eq("parent_id", entry.getKey());
            List<Organization> areaOrg = organizationDao.selectList(organizationQueryWrapper);
            if (!areaOrg.isEmpty()) {
                for (Organization area : areaOrg) {
                    buildingDB.put(area.getName(), null);
                }
            }
            for (AreaDTO areaDTO : value) {
                if (buildingDB.containsKey(areaDTO.getName()) || map.containsKey(areaDTO.getName())) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("名称重复");
                    errorSpace.setObj(areaDTO);
                    errors.add(errorSpace);
                } else {
                    map.put(areaDTO.getName(), areaDTO);
                }
            }
            List<Area> correctList = new ArrayList<>();
            for (Map.Entry<String, AreaDTO> entry1 : map.entrySet()) {
                correctList.add(entry1.getValue());
            }

            // code 校验
            Map<String, AreaDTO> codeMap = new HashMap<>();
            Map<String, Object> codeMapDB = new HashMap<>();
            // 这里仅校验同一个项目下的编码重复
            QueryWrapper<Organization> organizationQueryWrapper1 = new QueryWrapper<>();
            organizationQueryWrapper1.select("code");
            organizationQueryWrapper1.eq("project_id", organization.getProjectId());
            organizationQueryWrapper1.eq("type", OrganizationTypeEnum.AREA.id);
            organizationQueryWrapper1.isNotNull("code");
            List<Organization> organizations1 = organizationDao.selectList(organizationQueryWrapper1);
            if (!organizations1.isEmpty()) {
                codeMapDB = organizations1.stream().collect(Collectors.toMap(Organization::getCode, Organization::getCode));
            }
            for (AreaDTO areaDTO : value) {
                if (!StringUtils.isEmpty(areaDTO.getCode()) && (codeMapDB.containsKey(areaDTO.getCode()) || codeMap.containsKey(areaDTO.getCode()))) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("编码重复");
                    errorSpace.setObj(areaDTO);
                    errors.add(errorSpace);
                } else {
                    codeMap.put(areaDTO.getName(), areaDTO);
                }
            }
            correctList = correctList.stream().filter(i -> codeMap.containsKey(i.getName())).collect(Collectors.toList());
            if (correctList.isEmpty()) {
                log.info("校验后没有合适的数据");
                continue;
            }
            try {
                this.saveBatch(correctList);
            } catch (Exception e) {
                log.error("批量保存失败 {}", e.getMessage());
                for (Area area : correctList) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("批量保存失败");
                    errorSpace.setObj(area);
                    errors.add(errorSpace);
                }
                continue;
            }
            // 保存组织信息
            List<Organization> organizations = new ArrayList<>();
            for (Area area : correctList) {
                Organization organization1 = new Organization();
                organization1.setName(area.getName());
                organization1.setParentId(area.getParentId());
                if (StringUtils.isEmpty(area.getCode())) {
                    String code = AutoCodeUtils.codeFormat(CodePrefixConstant.AREA_PREFIX, area.getId(), CodePrefixConstant.CODE_LENGTH);
                    area.setCode(code);
                }
                organization1.setSortField(area.getSortField());
                organization1.setCode(area.getCode());
                organization1.setType(OrganizationTypeEnum.AREA.id.intValue());
                organization1.setLevel(organization.getLevel() + 1);
                organization1.setIndustryId(organization.getIndustryId());
                organization1.setEnterpriseId(organization.getEnterpriseId());
                if (null != organization.getProjectId()) {
                    organization1.setProjectId(organization.getProjectId());
                }
                organizations.add(organization1);
            }
            organizationService.saveBatch(organizations);

            // 统一分组下名称不会重复
            Map<String, Integer> collect1 = organizations.stream().collect(Collectors.toMap(Organization::getName, Organization::getId));

            for (Area area : correctList) {
                area.setOrganizationId(collect1.get(area.getName()));
            }
            this.updateBatchById(correctList);
        }
        return ResultJson.success(errors);
    }
}
